package com.ushine.web.component.exception;


import com.ushine.web.component.http.HttpResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.annotation.Priority;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @Author yls
 * @Date 2020/3/30 14:39
 * @Description 统一封装业务的异常处理
 * @Version 1.0
 **/
//ControllerAdvice：该注解是定义统一的异常处理，
//basePackages：定义扫描哪些包(basePackages = "com.authority.manager")

@ControllerAdvice
@Priority(1)
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 功能描述:
     * 〈 日志记录权限异常信息 〉
     *
     * @param e 异常信息
     * @return : void
     * @author : yls
     * @date : 2022/3/26 11:44
     */
    private void printException(String methodName, Throwable e) {
        log.error("全局异常捕获：{}", methodName, e);
    }

    /**
     * <h3>处理全局异常进行</h3>
     *
     * @param ex 异常类型
     * @return 视图数据
     */
    @ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public HttpResponseVO<Object> errorHandler(Throwable ex) {
        printException("errorHandler", ex);
        HttpResponseVO<Object> httpResponseVO = new HttpResponseVO<>();
        httpResponseVO.setCode(500);
        httpResponseVO.setData(ex.getMessage());
        httpResponseVO.setMsg(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR.getErrorMsg());
        return httpResponseVO;
    }


    /**
     * 功能描述:
     * 〈ExceptionHandler 用来定义函数针对的异常类型，可以传入多个需要捕获的异常。〉
     *
     * @param e 异常信息
     * @return : void
     * @author : yls
     * @date : 2022/3/11 16:03
     */
    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    public HttpResponseVO<Object> defaultErrorHandler(HttpServletRequest request, BusinessException e) {
        printException("defaultErrorHandler", e);
        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
    }

    /**
     * mybatis 相关异常
     */
    @ResponseBody
    @ExceptionHandler(MyBatisSystemException.class)
    public HttpResponseVO<Object> persistenceExceptionHandler(MyBatisSystemException e) {
        printException("persistenceExceptionHandler", e);
        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_SERVER_DANGER);
    }

    /**
     * 功能描述:
     * 〈 数据库唯一性验证 〉
     *
     * @param e 异常信息
     * @return : com.ushine.web.component.http.HttpResponseVO<java.lang.Object>
     * @author : yls
     * @date : 2022/3/26 9:29
     */
    @ResponseBody
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public HttpResponseVO<Object> sqlIntegrityConstraintViolationException(SQLIntegrityConstraintViolationException e) {
        printException("sqlIntegrityConstraintViolationException", e);
        return new HttpResponseVO<>().error(ServiceExceptionEnum.EXIST_SAME_NAME_DATA);
    }


    /**
     * 功能描述:
     * 〈 捕获业务异常信息并返回前台 〉
     *
     * @param e 自定义业务异常信息
     * @return : com.ushine.web.component.http.HttpResponseVO<java.lang.Object>
     * @author : yls
     * @date : 2022/3/26 9:32
     */
    @ResponseBody
    @ExceptionHandler(ServiceException.class)
    public HttpResponseVO<Object> serviceException(ServiceException e) {
        printException("serviceException", e);
        return new HttpResponseVO<>().error(e.getMessage());
    }


    /**
     * 功能描述:
     * 〈处理所有参数校验时抛出的异常〉
     *
     * @param ex 校验异常统一返回信息
     * @return : com.ushine.web.component.http.HttpResponseVO
     * @author : yls
     * @date : 2022/2/8 15:16
     */
    @ResponseBody
    @ExceptionHandler(value = ValidationException.class)
    public HttpResponseVO<List<String>> handleBindException(ValidationException ex) {
        printException("handleBindException", ex);
        List<String> errors = new ArrayList<>();
        if (ex instanceof ConstraintViolationException) {
            ConstraintViolationException exs = (ConstraintViolationException) ex;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                String errorMsg = item.getMessage();
                errors.add(errorMsg);
            }
        }
        log.error("数据校验异常：{}", errors);
        return new HttpResponseVO<List<String>>().errorValid(errors);
    }


    /**
     * 方法参数校验
     */
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public HttpResponseVO<List<String>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        printException("handleMethodArgumentNotValidException", e);
        List<String> errors = new ArrayList<>();
        BindingResult bindingResult = e.getBindingResult();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();
        fieldErrors.forEach(fieldError -> errors.add(fieldError.getDefaultMessage()));
        return new HttpResponseVO<List<String>>().errorValid(errors);
    }

    /**
     * 数据库异常
     */
    @ResponseBody
    @ExceptionHandler(value = CannotAcquireLockException.class)
    public HttpResponseVO<Object> leaveApplySign(CannotAcquireLockException e) {
        printException("leaveApplySign", e);
        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_SERVER_BUSY);
    }

    /**
     * 没有权限操作
     */
    @ResponseBody
    @ExceptionHandler(value = AccessDeniedException.class)
    public HttpResponseVO<Object> accessDeniedHandler(AccessDeniedException e) {
        printException("accessDeniedHandler", e);
        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_ACCESS_DENIED_ERROR);
    }


    /**
     * 文件上传超出大小异常
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public HttpResponseVO<Object> uploadMaxUploadSizeException(HttpServletRequest request, MaxUploadSizeExceededException e) {
        printException("uploadMaxUploadSizeException", e);
        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_UPLOAD_MAX_SIZE_ERROR);
    }

//    /**
//     * 空指针异常
//     */
//    @ResponseBody
//    @ExceptionHandler(NullPointerException.class)
//    public HttpResponseVO<Object> nullPointerExceptionHandler(NullPointerException e) {
//       printException("nullPointerExceptionHandler",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 类型转换异常
//     */
//    @ResponseBody
//    @ExceptionHandler(ClassCastException.class)
//    public HttpResponseVO<Object> classCastExceptionHandler(ClassCastException e) {
//       printException("classCastExceptionHandler",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//
//    /**
//     * 数组越界异常
//     */
//    @ResponseBody
//    @ExceptionHandler(ArrayIndexOutOfBoundsException.class)
//    public HttpResponseVO<Object> arrayIndexOutOfBoundsException(ArrayIndexOutOfBoundsException e) {
//       printException("arrayIndexOutOfBoundsException",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * IO异常
//     */
//    @ResponseBody
//    @ExceptionHandler(IOException.class)
//    public HttpResponseVO<Object> ioExceptionHandler(IOException e) {
//       printException("ioExceptionHandler",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 未知方法异常
//     */
//    @ResponseBody
//    @ExceptionHandler(NoSuchMethodException.class)
//    public HttpResponseVO<Object> noSuchMethodExceptionHandler(NoSuchMethodException e) {
//       printException("noSuchMethodExceptionHandler",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 400错误
//     */
//    @ResponseBody
//    @ExceptionHandler({HttpMessageNotReadableException.class})
//    public HttpResponseVO<Object> requestNotReadable(HttpMessageNotReadableException e) {
//       printException("requestNotReadable",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 400错误
//     */
//    @ResponseBody
//    @ExceptionHandler({TypeMismatchException.class})
//    public HttpResponseVO<Object> requestTypeMismatch(TypeMismatchException e) {
//       printException("requestTypeMismatch",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 400错误
//     */
//    @ResponseBody
//    @ExceptionHandler({MissingServletRequestParameterException.class})
//    public HttpResponseVO<Object> requestMissingServletRequest(MissingServletRequestParameterException e) {
//       printException("requestMissingServletRequest",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//
//    /**
//     * 405错误
//     */
//    @ResponseBody
//    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
//    public HttpResponseVO<Object> requestMethodNotSupported(HttpRequestMethodNotSupportedException e) {
//       printException("requestMethodNotSupported",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 406错误
//     */
//    @ResponseBody
//    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
//    public HttpResponseVO<Object> requestMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException e) {
//       printException("requestMediaTypeNotAcceptable",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//    /**
//     * 500错误
//     */
//    @ResponseBody
//    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
//    public HttpResponseVO<Object> conversionNotSupported(RuntimeException e) {
//       printException("conversionNotSupported",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//
//
//    /**
//     * 除数不能为0
//     */
//    @ResponseBody
//    @ExceptionHandler({ArithmeticException.class})
//    public HttpResponseVO<Object> arithmeticException(ArithmeticException e) {
//       printException("arithmeticException",e);
//        return new HttpResponseVO<>().error(BaseErrorEnum.SYSTEM_INTERNAL_SERVER_ERROR);
//    }
//


}
